﻿using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using NSubstitute;
using Phoenix.Frames;
using Phoenix.Framework;
using Xunit;

namespace Phoenix.Tests.Navigation
{
    public class ControllerActionsTests
    {
        readonly InvokeActionBuilder subject;
        readonly ControllerActionContext currentContext;

        public ControllerActionsTests()
        {
            currentContext = PhoenixObjectMother.CreateContext(new ControllerAction("Test", "Test", null));
            subject = new InvokeActionBuilder(currentContext);
        }

        [Fact]
        public void can_execute_controller_action_not_specifying_frame()
        {
            // arrange
            var controllerAction = new ControllerAction("C", "A", null);

            // act
            subject.InvokeAction(controllerAction);

            // assert
            currentContext.Host.ActionInvoker
                .Received()
                .InvokeAction(Arg.Is(MatchingRequest(controllerAction)));
        }

        [Fact]
        public void can_execute_controller_action_specifying_frame()
        {
            // arrange
            var targetFrame = Substitute.For<INavigationFrame>();
            var controllerAction = new ControllerAction("C", "A", null);

            // act
            subject.InvokeAction(targetFrame, controllerAction);

            // assert
            currentContext.Host.ActionInvoker.Received()
                .InvokeAction(Arg.Is(MatchingRequest(controllerAction, null, targetFrame)));
        }

        Expression<Predicate<InvokeActionRequest>> MatchingRequest(
            ControllerAction controllerAction,
            Predicate<IEnumerable<ControllerActionParameter>> parameterPredicate = null,
            INavigationFrame frame = null)
        {
            return c => c.CurrentContext == currentContext &&
                        c.Target == controllerAction &&
                        (parameterPredicate == null || parameterPredicate(c.Parameters)) &&
                        (frame == null || c.TargetFrame == frame);
        }
    }
}